ããªãŒèµ°æ»ã®ããã®ãžã§ããªãã¯Visitorãã¿ãŒã³ãç¿åŸãã¢ã«ãŽãªãºã ãšããªãŒæ§é ãåé¢ããããæè»ã§ä¿å®æ§ã®é«ãã³ãŒããå®çŸããããã®å æ¬çãªã¬ã€ãã§ãã
æè»ãªããªãŒèµ°æ»ãè§£ãæŸã€ïŒãžã§ããªãã¯Visitorãã¿ãŒã³ã培åºè§£èª¬
ãœãããŠã§ã¢å·¥åŠã®äžçã§ã¯ãéå±€çãªããªãŒç¶ã®æ§é ã«æŽçãããããŒã¿ã«é »ç¹ã«åºããããŸããã³ã³ãã€ã©ãç§ãã¡ã®ã³ãŒããçè§£ããããã«äœ¿çšããæœè±¡æ§ææšïŒASTïŒããããŠã§ããåããDocument Object ModelïŒDOMïŒããããŠåçŽãªãã¡ã€ã«ã·ã¹ãã ã«è³ããŸã§ãããªãŒã¯è³ãæã«ååšããŸãããããã®æ§é ãæ±ãéã®åºæ¬çãªã¿ã¹ã¯ã¯ãèµ°æ»ïŒtraversalïŒã§ããããã¯ãäœããã®æäœãå®è¡ããããã«åããŒãã蚪åããããšã§ãããããã課é¡ãšãªãã®ã¯ããããã¯ãªãŒã³ã§ä¿å®æ§ãé«ããæ¡åŒµå¯èœãªæ¹æ³ã§è¡ãããšã§ãã
åŸæ¥ã®ã¢ãããŒãã§ã¯ãæäœããžãã¯ãããŒãã¯ã©ã¹å ã«çŽæ¥åã蟌ãŸããããšããããããŸãããããã¯ãã¢ããªã·ãã¯ã§å¯çµåãªã³ãŒãã«ã€ãªãããäž»èŠãªãœãããŠã§ã¢èšèšååã«éåããŸããããªãã£ããªã³ã¿ãããªããŒã¿ã®ãããªæ°ããæäœã远å ããå Žåããã¹ãŠã®ããŒãã¯ã©ã¹ã倿Žããå¿ èŠããããã·ã¹ãã ãè匱ã§ä¿å®å°é£ãªãã®ã«ããŠããŸããŸãã
å€å žçãªVisitorãã¶ã€ã³ãã¿ãŒã³ã¯ãã¢ã«ãŽãªãºã ãšãããäœçšãããªããžã§ã¯ããåé¢ããããšã§ã匷åãªè§£æ±ºçãæäŸããŸããããããå€å žçãªãã¿ãŒã³ã«ããç¹ã«æ¡åŒµæ§ã«é¢ããŠéçããããŸããããã§ããžã§ããªãã¯Visitorãã¿ãŒã³ãç¹ã«ããªãŒèµ°æ»ã«é©çšãããå Žåã«ããã®ç䟡ãçºæ®ãããŸãããžã§ããªãã¯ããã³ãã¬ãŒããããªã¢ã³ããšãã£ãçŸä»£ã®ããã°ã©ãã³ã°èšèªæ©èœã掻çšããããšã§ãããããããªãŒæ§é ãåŠçããããã®ãéåžžã«æè»ã§åå©çšå¯èœãã€åŒ·åãªã·ã¹ãã ãæ§ç¯ã§ããŸãã
ãã®åŸ¹åºè§£èª¬ã§ã¯ãå€å žçãªVisitorãã¿ãŒã³ããæŽç·Žããããžã§ããªãã¯ãªå®è£ ãžãšãããªããå°ããŸãã以äžã®å å®¹ãæ¢æ±ããŸãïŒ
- å€å žçãªVisitorãã¿ãŒã³ãšãã®åºæã®èª²é¡ã®å確èªã
- æäœãããã«åé¢ãããžã§ããªãã¯ã¢ãããŒããžã®é²åã
- ãžã§ããªãã¯ãªããªãŒèµ°æ»Visitorã®è©³çްãªã¹ããããã€ã¹ãããå®è£ ã
- èµ°æ»ããžãã¯ãšæäœããžãã¯ãåé¢ããããšã®èšãç¥ããªãã¡ãªããã
- ãã®ãã¿ãŒã³ãèšãç¥ããªã䟡å€ãæäŸããå®äžçã®ã¢ããªã±ãŒã·ã§ã³ã
ã³ã³ãã€ã©ãéçè§£æããŒã«ãUIãã¬ãŒã ã¯ãŒã¯ããŸãã¯è€éãªããŒã¿æ§é ã«äŸåããããããã·ã¹ãã ãæ§ç¯ããŠãããã©ããã«ãããããããã®ãã¿ãŒã³ãç¿åŸããããšã§ãããªãã®ã¢ãŒããã¯ãã£æèãšã³ãŒãã®å質ãåäžããã§ãããã
å€å žçãªVisitorãã¿ãŒã³ã®åæ€èš
ãžã§ããªãã¯ãªé²åãçè§£ããåã«ããã®åºç€ããã£ãããšçè§£ããŠããå¿ èŠããããŸãããGoFïŒGang of FourïŒãããã®èšå¿µç¢çãªèæž ãã¶ã€ã³ãã¿ãŒã³ïŒåå©çšå¯èœãªãªããžã§ã¯ãæåãœãããŠã§ã¢ã®èŠçŽ ã§èšè¿°ããVisitorãã¿ãŒã³ã¯ãæ¢åã®ãªããžã§ã¯ãæ§é ã倿Žããã«æ°ããæäœããã®æ§é ã«è¿œå ã§ããæ¯ãèããã¿ãŒã³ã§ãã
ããã解決ããåé¡
NumberNodeïŒãªãã©ã«å€ïŒãAdditionNodeïŒ2ã€ã®éšååŒå ç®ã衚ãïŒãªã©ãç°ãªãããŒãã¿ã€ãã§æ§æãããåçŽãªç®è¡åŒããªãŒãæ³åããŠã¿ãŠãã ããããã®ããªãŒã«å¯ŸããŠãããã€ãã®ç°ãªãæäœãå®è¡ããããšæããããããŸããã
- è©äŸ¡ïŒ åŒã®æçµçãªæ°å€çµæãèšç®ããŸãã
- ããªãã£ããªã³ãïŒ "(5 + 3)" ã®ãããªäººéãèªããæåå衚çŸãçæããŸãã
- åãã§ãã¯ïŒ æäœãé¢äžããåã«å¯ŸããŠæå¹ã§ããããšãæ€èšŒããŸãã
çŽ æŽãªã¢ãããŒãã¯ãåºåºã®`Node`ã¯ã©ã¹ã«`evaluate()`ã`print()`ã`typeCheck()`ã®ãããªã¡ãœããã远å ããããããã®å ·è±¡ããŒãã¯ã©ã¹ã§ãªãŒããŒã©ã€ãããããšã§ããããããã¯ãé¢é£ã®ãªãããžãã¯ã§ããŒãã¯ã©ã¹ãè¥å€§åãããŸããæ°ããæäœãèæ¡ãããã³ã«ãéå±€å ã®ãã¹ãŠã®ããŒãã¯ã©ã¹ã«æãå ããå¿ èŠããããŸããããã¯ããœãããŠã§ã¢ãšã³ãã£ãã£ã¯æ¡åŒµã«å¯ŸããŠéãããä¿®æ£ã«å¯ŸããŠéããããã¹ãã§ãããšè¿°ã¹ããªãŒãã³ã»ã¯ããŒãºãã®ååã«éåããŸãã
å€å žçãªè§£æ±ºçïŒããã«ãã£ã¹ããã
Visitorãã¿ãŒã³ã¯ã2ã€ã®æ°ããéå±€ãããªãã¡Visitoréå±€ãšElementéå±€ïŒç§ãã¡ã®ããŒãïŒãå°å ¥ããããšã§ãã®åé¡ã解決ããŸãããã®éæ³ã¯ãããã«ãã£ã¹ããããšåŒã°ãããã¯ããã¯ã«ãããŸãã
äž»èŠãªåœ¹å²ã¯ä»¥äžã®éãã§ãïŒ
- èŠçŽ ã€ã³ã¿ãŒãã§ãŒã¹ (äŸ: `Node`): `accept(Visitor v)` ã¡ãœãããå®çŸ©ããŸãã
- å ·è±¡èŠçŽ (äŸ: `NumberNode`, `AdditionNode`): `accept` ã¡ãœãããå®è£ ããŸããå®è£ ã¯ã·ã³ãã«ã§ã`visitor.visit(this);`ãšãªããŸãã
- Visitorã€ã³ã¿ãŒãã§ãŒã¹: åå ·è±¡èŠçŽ åã«å¯ŸããŠãªãŒããŒããŒãããã`visit`ã¡ãœããã宣èšããŸããäŸãã°ã`visit(NumberNode n)` ãš `visit(AdditionNode n)` ã§ãã
- å ·è±¡Visitor (äŸ: `EvaluationVisitor`, `PrintVisitor`): ç¹å®ã®æäœãå®è¡ããããã«`visit`ã¡ãœãããå®è£ ããŸãã
åäœã¯æ¬¡ã®ãšããã§ãïŒ`node.accept(myVisitor)`ãåŒã³åºããŸãã`accept`ã®å éšã§ãããŒãã¯`myVisitor.visit(this)`ãåŒã³åºããŸãããã®æç¹ã§ãã³ã³ãã€ã©ã¯`this`ã®å ·è±¡åïŒäŸïŒ`AdditionNode`ïŒãš`myVisitor`ã®å ·è±¡åïŒäŸïŒ`EvaluationVisitor`ïŒãç¥ã£ãŠããŸãããããã£ãŠãæ£ãã`visit`ã¡ãœãããããªãã¡`EvaluationVisitor::visit(AdditionNode*)`ã«ãã£ã¹ãããã§ããŸãããã®2段éã®åŒã³åºãã¯ãåäžã®ä»®æ³é¢æ°åŒã³åºãã§ã¯éæã§ããªãããšãã€ãŸã2ã€ã®ç°ãªããªããžã§ã¯ãã®å®è¡æåã«åºã¥ããŠæ£ããã¡ãœããã解決ããããšãå®çŸããŸãã
å€å žçãªãã¿ãŒã³ã®éç
æŽç·ŽãããŠããäžæ¹ã§ãå€å žçãªVisitorãã¿ãŒã³ã«ã¯ãé²åããã·ã¹ãã ã§ã®äœ¿çšã劚ããéå€§ãªæ¬ ç¹ããããŸããããã¯ãèŠçŽ éå±€ã®ç¡¬çŽæ§ã§ãã
`Visitor`ã€ã³ã¿ãŒãã§ãŒã¹ã«ã¯ããã¹ãŠã®`ConcreteElement`åã«å¯Ÿå¿ãã`visit`ã¡ãœãããå«ãŸããŠããŸããæ°ããããŒãã¿ã€ãïŒäŸãã°`MultiplicationNode`ïŒã远å ãããå Žåãåºåºã®`Visitor`ã€ã³ã¿ãŒãã§ãŒã¹ã«æ°ãã`visit(MultiplicationNode n)`ã¡ãœããã远å ããå¿ èŠããããŸããããã«ãããã·ã¹ãã å ã«ååšãããã¹ãŠã®å ·è±¡Visitorã¯ã©ã¹ããã®æ°ããã¡ãœãããå®è£ ããããã«æŽæ°ãäœåãªããããŸããæ°ããæäœã远å ããéã«è§£æ±ºããåé¡ããæ°ããèŠçŽ åã远å ããéã«åã³çŸããã®ã§ããã·ã¹ãã ã¯æäœåŽã§ã¯å€æŽã«å¯ŸããŠéããããŠããŸãããèŠçŽ åŽã§ã¯å€§ããéããŠããŸãã
èŠçŽ éå±€ãšVisitoréå±€éã®ãã®åŸªç°äŸåæ§ã¯ãããæè»ã§ãžã§ããªãã¯ãªè§£æ±ºçãæ±ããäž»èŠãªåæ©ãšãªã£ãŠããŸãã
ãžã§ããªãã¯ãªé²åïŒããæè»ãªã¢ãããŒã
å€å žçãªãã¿ãŒã³ã®æ žãšãªãéçã¯ãVisitorã€ã³ã¿ãŒãã§ãŒã¹ãšå ·è±¡èŠçŽ åãšã®éã®éçãªã³ã³ãã€ã«æçµåã§ãããžã§ããªãã¯ãªã¢ãããŒãã¯ããã®çµåãè§£æ¶ããããšããŸããäžå¿çãªã¢ã€ãã¢ã¯ãæ£ãããã³ããªã³ã°ããžãã¯ãžã®ãã£ã¹ãããã®è²¬ä»»ãããªãŒããŒããŒããããã¡ãœããã®å³å¯ãªã€ã³ã¿ãŒãã§ãŒã¹ããç§»è¡ãããããšã§ãã
çŸä»£ã®C++ã¯ã匷åãªãã³ãã¬ãŒãã¡ã¿ããã°ã©ãã³ã°ãšæšæºã©ã€ãã©ãªæ©èœã§ãã`std::variant`ã®ãããªæ©èœã«ããããããå®è£ ããããã®éåžžã«ã¯ãªãŒã³ã§å¹ççãªæ¹æ³ãæäŸããŸããC#ãJavaã®ãããªèšèªã§ãããªãã¬ã¯ã·ã§ã³ããžã§ããªãã¯ã€ã³ã¿ãŒãã§ãŒã¹ã䜿çšããããšã§åæ§ã®ã¢ãããŒããéæã§ããŸãããããã©ãŒãã³ã¹ã®ãã¬ãŒããªããçºçããå¯èœæ§ããããŸãã
ç§ãã¡ã®ç®æšã¯ã以äžã®èŠä»¶ãæºããã·ã¹ãã ãæ§ç¯ããããšã§ãïŒ
- æ°ããããŒãåã®è¿œå ã¯å±æçã§ãããæ¢åã®ãã¹ãŠã®Visitorå®è£ ã«ãããé£éçãªå€æŽãå¿ èŠãšããŸããã
- æ°ããæäœã®è¿œå ã¯ãVisitorãã¿ãŒã³ã®æ¬æ¥ã®ç®æšãšäžèŽããã·ã³ãã«ã§ããç¶ããŸãã
- èµ°æ»ããžãã¯èªäœïŒäŸïŒå è¡é ãåŸè¡é ïŒã¯ãžã§ããªãã¯ã«å®çŸ©ã§ããããããæäœã§åå©çšã§ããŸãã
ãã®3ç¹ç®ããç§ãã¡ã®ãããªãŒèµ°æ»åå®è£ ãã®éµãšãªããŸããæäœãããŒã¿æ§é ããåé¢ããã ãã§ãªããèµ°æ»ã®è¡çºãšæäœã®è¡çºãåé¢ããŸãã
C++ã«ãããããªãŒèµ°æ»ã®ããã®ãžã§ããªãã¯Visitorã®å®è£
çŸä»£ã®C++ïŒC++17以éïŒã䜿çšããŠããžã§ããªãã¯Visitorãã¬ãŒã ã¯ãŒã¯ãæ§ç¯ããŸãã`std::variant`ã`std::unique_ptr`ãããã³ãã³ãã¬ãŒãã®çµã¿åããã«ãããåå®å šã§å¹ççããã€éåžžã«è¡šçŸåè±ããªãœãªã¥ãŒã·ã§ã³ãåŸãããŸãã
ã¹ããã1ïŒããªãŒããŒãæ§é ã®å®çŸ©
ãŸããããŒãåãå®çŸ©ããŸããããä»®æ³ã®`accept`ã¡ãœãããæã€åŸæ¥ã®ç¶æ¿éå±€ã®ä»£ããã«ãããŒããã·ã³ãã«ãªæ§é äœãšããŠå®çŸ©ããŸããæ¬¡ã«ã`std::variant`ã䜿çšããŠãä»»æã®ããŒãåãä¿æã§ããååãäœæããŸãã
ååž°çãªæ§é ïŒããŒããä»ã®ããŒããå«ãããªãŒïŒãå¯èœã«ããããã«ã¯ã鿥局ãå¿ èŠã§ãã`Node`æ§é äœã¯ããªã¢ã³ããã©ãããããã®åã«ã¯`std::unique_ptr`ã䜿çšããŸãã
ãã¡ã€ã«ïŒ `Nodes.h`
#include <memory> #include <variant> #include <vector> // Forward-declare the main Node wrapper struct Node; // Define the concrete node types as simple data aggregates struct NumberNode { double value; }; struct BinaryOpNode { enum class Operator { Add, Subtract, Multiply, Divide }; Operator op; std::unique_ptr<Node> left; std::unique_ptr<Node> right; }; struct UnaryOpNode { enum class Operator { Negate }; Operator op; std::unique_ptr<Node> operand; }; // Use std::variant to create a sum type of all possible node types using NodeVariant = std::variant<NumberNode, BinaryOpNode, UnaryOpNode>; // The main Node struct that wraps the variant struct Node { NodeVariant var; };
ãã®æ§é ã¯ããã§ã«å€§ããªæ¹åã§ããããŒãåã¯ãã¬ãŒã³ãªå€ãããŒã¿æ§é äœã§ããVisitorããããªãæäœã«ã€ããŠãç¥ããŸããã`FunctionCallNode`ã远å ããã«ã¯ãæ§é äœãå®çŸ©ããããã`NodeVariant`ãšã€ãªã¢ã¹ã«è¿œå ããã ãã§ããããã¯ãããŒã¿æ§é èªäœã«å¯Ÿããåäžã®ä¿®æ£ç¹ã§ãã
ã¹ããã2ïŒ`std::visit`ã«ãããžã§ããªãã¯Visitorã®äœæ
`std::visit`ãŠãŒãã£ãªãã£ã¯ããã®ãã¿ãŒã³ã®èŠã§ããããã¯ãåŒã³åºãå¯èœãªããžã§ã¯ãïŒé¢æ°ãã©ã ãããŸãã¯`operator()`ãæã€ãªããžã§ã¯ããªã©ïŒãš`std::variant`ãåãåããããªã¢ã³ãå ã§çŸåšã¢ã¯ãã£ããªåã«åºã¥ããŠãåŒã³åºãå¯èœãªããžã§ã¯ãã®æ£ãããªãŒããŒããŒããåŒã³åºããŸããããããç§ãã¡ã®åå®å šãªã³ã³ãã€ã«æããã«ãã£ã¹ãããã¡ã«ããºã ã§ãã
Visitorã¯ãããªã¢ã³ãå ã®ååã«å¯ŸããŠãªãŒããŒããŒãããã`operator()`ãæã€ã·ã³ãã«ãªæ§é äœãšãªããŸãã
ãããå®éã«èŠãŠã¿ãããã«ãã·ã³ãã«ãªããªãã£ããªã³ã¿VisitorãäœæããŸãããã
ãã¡ã€ã«ïŒ `PrettyPrinter.h`
#include "Nodes.h" #include <string> #include <iostream> struct PrettyPrinter { // Overload for NumberNode void operator()(const NumberNode& node) const { std::cout << node.value; } // Overload for UnaryOpNode void operator()(const UnaryOpNode& node) const { std::cout << "(-"; std::visit(*this, node.operand->var); // Recursive visit std::cout << ")"; } // Overload for BinaryOpNode void operator()(const BinaryOpNode& node) const { std::cout << "("; std::visit(*this, node.left->var); // Recursive visit switch (node.op) { case BinaryOpNode::Operator::Add: std::cout << " + "; break; case BinaryOpNode::Operator::Subtract: std::cout << " - "; break; case BinaryOpNode::Operator::Multiply: std::cout << " * "; break; case BinaryOpNode::Operator::Divide: std::cout << " / "; break; } std::visit(*this, node.right->var); // Recursive visit std::cout << ")"; } };
ããã§äœãèµ·ããŠãããã«æ³šç®ããŠãã ãããèµ°æ»ããžãã¯ïŒåã蚪åããïŒãšæäœããžãã¯ïŒæ¬åŒ§ãšæŒç®åãå°å·ããïŒã`PrettyPrinter`å éšã§æ··åšããŠããŸããããã¯æ©èœããŸãããããã«æ¹åã§ããŸããç§ãã¡ã¯äœããšã©ã®ããã«ãåé¢ã§ããŸãã
ã¹ããã3ïŒäž»åœ¹ç»å Ž - ãžã§ããªãã¯ãªããªãŒèµ°æ»Visitor
ããã§ãæ žãšãªãã³ã³ã»ãããå°å ¥ããŸããããã¯ãèµ°æ»æŠç¥ãã«ãã»ã«åããåå©çšå¯èœãª`TreeWalker`ã§ãããã®`TreeWalker`ã¯ããèªäœãVisitorã§ããããã®å¯äžã®ä»äºã¯ããªãŒã蟿ãããšã§ããèµ°æ»äžã®ç¹å®ã®ãã€ã³ãã§å®è¡ãããä»ã®é¢æ°ïŒã©ã ããŸãã¯é¢æ°ãªããžã§ã¯ãïŒãåãåããŸãã
ç°ãªãæŠç¥ããµããŒãã§ããŸãããäžè¬çã§åŒ·åãªæŠç¥ã¯ããpre-visitãïŒåã蚪åããåïŒãšãpost-visitãïŒåã蚪åããåŸïŒã®ããã¯ãæäŸããããšã§ããããã¯ãå è¡é ãšåŸè¡é ã®èµ°æ»ã¢ã¯ã·ã§ã³ã«çŽæ¥å¯Ÿå¿ããŸãã
ãã¡ã€ã«ïŒ `TreeWalker.h`
#include "Nodes.h" #include <functional> template <typename PreVisitAction, typename PostVisitAction> struct TreeWalker { PreVisitAction pre_visit; PostVisitAction post_visit; // Base case for nodes with no children (terminals) void operator()(const NumberNode& node) { pre_visit(node); post_visit(node); } // Case for nodes with one child void operator()(const UnaryOpNode& node) { pre_visit(node); std::visit(*this, node.operand->var); // Recurse post_visit(node); } // Case for nodes with two children void operator()(const BinaryOpNode& node) { pre_visit(node); std::visit(*this, node.left->var); // Recurse left std::visit(*this, node.right->var); // Recurse right post_visit(node); } }; // Helper function to make creating the walker easier template <typename Pre, typename Post> auto make_tree_walker(Pre pre, Post post) { return TreeWalker<Pre, Post>{pre, post}; }
ãã®`TreeWalker`ã¯åé¢ã®åäœã§ããããã¯ãå°å·ãè©äŸ¡ãåãã§ãã¯ã«ã€ããŠäœãç¥ããŸããããã®å¯äžã®ç®çã¯ãããªãŒã®æ·±ãåªå èµ°æ»ãå®è¡ããæäŸãããããã¯ãåŒã³åºãããšã§ãã`pre_visit`ã¢ã¯ã·ã§ã³ã¯å è¡é ã«å®è¡ããã`post_visit`ã¢ã¯ã·ã§ã³ã¯åŸè¡é ã«å®è¡ãããŸããã©ã®ã©ã ããå®è£ ããããéžæããããšã§ããŠãŒã¶ãŒã¯ããããçš®é¡ã®æäœãå®è¡ã§ããŸãã
ã¹ããã4ïŒ`TreeWalker`ã䜿çšããŠåŒ·åã§åé¢ãããæäœãå®çŸãã
次ã«ãç§ãã¡ã®`PrettyPrinter`ããªãã¡ã¯ã¿ãªã³ã°ããæ°ãããžã§ããªãã¯`TreeWalker`ã䜿çšããŠ`EvaluationVisitor`ãäœæããŸããããæäœããžãã¯ã¯ãã·ã³ãã«ãªã©ã ããšããŠè¡šçŸãããããã«ãªããŸãã
ã©ã ãåŒã³åºãéã§ç¶æ ïŒè©äŸ¡ã¹ã¿ãã¯ãªã©ïŒãæž¡ãã«ã¯ã倿°ãåç §ã§ãã£ããã£ã§ããŸãã
ãã¡ã€ã«ïŒ `main.cpp`
#include "Nodes.h" #include "TreeWalker.h" #include <iostream> #include <string> #include <vector> // Helper for creating a generic lambda that can handle any node type template<class... Ts> struct Overloaded : Ts... { using Ts::operator()...; }; template<class... Ts> Overloaded(Ts...) -> Overloaded<Ts...>; int main() { // Let's build a tree for the expression: (5 + (10 * 2)) auto num5 = std::make_unique<Node>(Node{NumberNode{5.0}}); auto num10 = std::make_unique<Node>(Node{NumberNode{10.0}}); auto num2 = std::make_unique<Node>(Node{NumberNode{2.0}}); auto mult = std::make_unique<Node>(Node{BinaryOpNode{ BinaryOpNode::Operator::Multiply, std::move(num10), std::move(num2) }}); auto root = std::make_unique<Node>(Node{BinaryOpNode{ BinaryOpNode::Operator::Add, std::move(num5), std::move(mult) }}); std::cout << "--- Pretty Printing Operation ---\n"; auto printer_pre_visit = Overloaded { [](const NumberNode& node) { std::cout << node.value; }, [](const UnaryOpNode&) { std::cout << "(-"; }, [](const BinaryOpNode&) { std::cout << "("; } }; auto printer_post_visit = Overloaded { [](const NumberNode&) {}, // Do nothing [](const UnaryOpNode&) { std::cout << ")"; }, [](const BinaryOpNode& node) { switch (node.op) { case BinaryOpNode::Operator::Add: std::cout << " + "; break; case BinaryOpNode::Operator::Subtract: std::cout << " - "; break; case BinaryOpNode::Operator::Multiply: std::cout << " * "; break; case BinaryOpNode::Operator::Divide: std::cout << " / "; break; } } }; // This will not work as the children are visited in between pre and post. // Let's refine the walker to be more flexible for an in-order print. // A better approach for pretty printing is to have an "in-visit" hook. // For simplicity, let's re-structure the printing logic slightly. // Or better, let's create a dedicated PrintWalker. Let's stick to pre/post for now and show evaluation which is a better fit. std::cout << "\n--- Evaluation Operation ---\n"; std::vector<double> eval_stack; auto eval_pre_visit = [](const auto&){}; // Do nothing on pre-visit auto eval_post_visit = Overloaded { [&](const NumberNode& node) { eval_stack.push_back(node.value); }, [&](const UnaryOpNode& node) { double operand = eval_stack.back(); eval_stack.pop_back(); eval_stack.push_back(-operand); }, [&](const BinaryOpNode& node) { double right = eval_stack.back(); eval_stack.pop_back(); double left = eval_stack.back(); eval_stack.pop_back(); switch(node.op) { case BinaryOpNode::Operator::Add: eval_stack.push_back(left + right); break; case BinaryOpNode::Operator::Subtract: eval_stack.push_back(left - right); break; case BinaryOpNode::Operator::Multiply: eval_stack.push_back(left * right); break; case BinaryOpNode::Operator::Divide: eval_stack.push_back(left / right); break; } } }; auto evaluator = make_tree_walker(eval_pre_visit, eval_post_visit); std::visit(evaluator, root->var); std::cout << "Evaluation result: " << eval_stack.back() << std::endl; return 0; }
è©äŸ¡ããžãã¯ãèŠãŠãã ãããããã¯åŸè¡é èµ°æ»ã«å®ç§ã«é©åããŠããŸããç§ãã¡ã¯ãåããŒãã®å€ãèšç®ããã¹ã¿ãã¯ã«ããã·ã¥ãããåŸã«ã®ã¿æäœãå®è¡ããŸãã`eval_post_visit`ã©ã ãã¯`eval_stack`ããã£ããã£ããè©äŸ¡ã®ããã®ãã¹ãŠã®ããžãã¯ãå«ãã§ããŸãããã®ããžãã¯ã¯ãããŒãå®çŸ©ã`TreeWalker`ããå®å šã«åé¢ãããŠããŸããç§ãã¡ã¯ãããŒã¿æ§é ïŒNodesïŒãèµ°æ»ã¢ã«ãŽãªãºã ïŒ`TreeWalker`ïŒããããŠæäœããžãã¯ïŒã©ã ãïŒãšããçŸãã3ã€ã®é¢å¿ã®åé¢ãéæããŸããã
ãžã§ããªãã¯Visitorã¢ãããŒãã®ã¡ãªãã
ãã®å®è£ æŠç¥ã¯ãç¹ã«å€§èŠæš¡ã§é·æã«ããããœãããŠã§ã¢ãããžã§ã¯ãã«ãããŠã倧ããªå©ç¹ããããããŸãã
æ¯é¡ãªãæè»æ§ãšæ¡åŒµæ§
ãããäž»ãªå©ç¹ã§ããæ°ããæäœã远å ããã®ã¯ç°¡åã§ããæ°ããã©ã ãã®ã»ãããèšè¿°ããããã`TreeWalker`ã«æž¡ãã ãã§ããæ¢åã®ã³ãŒãã«ã¯äžåæãå ããŸãããããã¯ãªãŒãã³ã»ã¯ããŒãºãã®ååã«å®å šã«æºæ ããŠããŸããæ°ããããŒãåã远å ããã«ã¯ãæ§é äœã远å ãã`std::variant`ãšã€ãªã¢ã¹ãæŽæ°ããïŒåäžã®å±æçãªå€æŽïŒã ãã§ããããã®åŸããããåŠçããå¿ èŠãããVisitorãæŽæ°ããŸããã³ã³ãã€ã©ã¯ãã©ã®VisitorïŒãªãŒããŒããŒããããã©ã ãïŒãçŸåšãªãŒããŒããŒããæ¬ ããŠãããã芪åã«æããŠãããŸãã
åªããé¢å¿ã®åé¢
ç§ãã¡ã¯ã3ã€ã®ç°ãªã責任ãåé¢ããŸããïŒ
- ããŒã¿è¡šçŸïŒ `Node`æ§é äœã¯ã·ã³ãã«ã§ãäžæŽ»æ§ãªããŒã¿ã³ã³ããã§ãã
- èµ°æ»ã¡ã«ãã¯ã¹ïŒ `TreeWalker`ã¯ã©ã¹ã¯ãããªãŒæ§é ãã©ã®ããã«ããã²ãŒããããã®ããžãã¯ãæä»çã«ææããŸããã·ã¹ãã ã®ä»ã®éšåã倿Žããããšãªããç°¡åã«`InOrderTreeWalker`ã`BreadthFirstTreeWalker`ãäœæã§ããŸãã
- æäœããžãã¯ïŒ ãŠã©ãŒã«ãŒã«æž¡ãããã©ã ãã¯ãç¹å®ã®ã¿ã¹ã¯ïŒè©äŸ¡ãå°å·ãåãã§ãã¯ãªã©ïŒã®ããã®ç¹å®ã®ããžãã¹ããžãã¯ãå«ãã§ããŸãã
ãã®åé¢ã«ãããã³ãŒãã¯çè§£ããããããã¹ããããããä¿å®ãããããªããŸããåã³ã³ããŒãã³ãã«ã¯ãåäžã®æç¢ºã«å®çŸ©ããã責任ããããŸãã
匷åãããåå©çšæ§
`TreeWalker`ã¯ç¡éã«åå©çšå¯èœã§ããèµ°æ»ããžãã¯ã¯äžåºŠæžãã°ãç¡éã®æ°ã®æäœã«é©çšã§ããŸããããã«ãããã³ãŒãã®éè€ãæžããæ°ããVisitorããšã«èµ°æ»ããžãã¯ãåå®è£ ããããšããçãããã°ã®å¯èœæ§ãäœæžãããŸãã
ç°¡æœã§è¡šçŸåè±ããªã³ãŒã
çŸä»£ã®C++æ©èœã«ãããçµæãšããŠåŸãããã³ãŒãã¯ããã°ãã°å€å žçãªVisitorå®è£ ãããç°¡æœã«ãªããŸããã©ã ãã䜿çšãããšãæäœããžãã¯ã䜿çšãããå Žæã§çŽæ¥å®çŸ©ã§ãããããã·ã³ãã«ã§å±æçãªæäœã®å¯èªæ§ãåäžããŸããã©ã ãã®ã»ããããVisitorãäœæããããã®`Overloaded`ãã«ãæ§é äœã¯ãVisitorå®çŸ©ãã¯ãªãŒã³ã«ä¿ã€ããã®äžè¬çã§åŒ·åãªã€ãã£ãªã ã§ãã
æœåšçãªãã¬ãŒããªããšèæ ®äºé
äžèœã®ãã¿ãŒã³ã¯ãããŸãããé¢äžãããã¬ãŒããªããçè§£ããããšãéèŠã§ãã
åæèšå®ã®è€éã
`std::variant`ãšãžã§ããªãã¯`TreeWalker`ã䜿çšãã`Node`æ§é ã®åæèšå®ã¯ãçŽæ¥çãªååž°é¢æ°åŒã³åºããããè€éã«æãããããããããŸããããã®ãã¿ãŒã³ã¯ãããªãŒæ§é ãå®å®ããŠãããæéã®çµéãšãšãã«æäœã®æ°ãå¢å ããããšãäºæ³ãããã·ã¹ãã ã§æå€§ã®å©çããããããŸããéåžžã«ã·ã³ãã«ã§äžåºŠéãã®ããªãŒåŠçã¿ã¹ã¯ã®å Žåãããã¯ãããããããããŸããã
ããã©ãŒãã³ã¹
`std::visit`ã䜿çšããC++ã«ããããã®ãã¿ãŒã³ã®ããã©ãŒãã³ã¹ã¯åªããŠããŸãã`std::visit`ã¯éåžžãã³ã³ãã€ã©ã«ãã£ãŠé«åºŠã«æé©åããããžã£ã³ãããŒãã«ã䜿çšããŠå®è£ ãããŠããããã£ã¹ãããã¯éåžžã«é«éã§ãããä»®æ³é¢æ°åŒã³åºããããéãããšããããããŸãããªãã¬ã¯ã·ã§ã³ãèŸæžããŒã¹ã®åã«ãã¯ã¢ããã«äŸåããŠåæ§ã®ãžã§ããªãã¯ãªåäœãå®çŸããå¯èœæ§ã®ããä»ã®èšèªã§ã¯ãå€å žçãªéçãã£ã¹ãããVisitorãšæ¯èŒããŠãé¡èãªããã©ãŒãã³ã¹ãªãŒããŒããããçºçããå¯èœæ§ããããŸãã
èšèªäŸåæ§
ãã®ç¹å®ã®å®è£ ã®åªé ããšå¹çæ§ã¯ãC++17ã®æ©èœã«å€§ããäŸåããŠããŸããååã¯è»¢çšå¯èœã§ãããä»ã®èšèªã§ã®å®è£ 詳现ã¯ç°ãªããŸããäŸãã°ãJavaã§ã¯ãææ°ããŒãžã§ã³ã§ã¯sealed interfaceãšãã¿ãŒã³ãããã³ã°ã䜿çšããããå€ãããŒãžã§ã³ã§ã¯ããåé·ãªãããããŒã¹ã®ãã£ã¹ãããã£ã䜿çšããããããããããŸããã
å®äžçã§ã®ã¢ããªã±ãŒã·ã§ã³ãšãŠãŒã¹ã±ãŒã¹
ããªãŒèµ°æ»ã®ããã®ãžã§ããªãã¯Visitorãã¿ãŒã³ã¯åãªãåŠè¡çãªæŒç¿ã§ã¯ãããŸãããããã¯å€ãã®è€éãªãœãããŠã§ã¢ã·ã¹ãã ã®åºç€ã§ãã
- ã³ã³ãã€ã©ãšã€ã³ã¿ããªã¿ïŒ ãããå žåçãªãŠãŒã¹ã±ãŒã¹ã§ããæœè±¡æ§ææšïŒASTïŒã¯ãç°ãªããVisitorããŸãã¯ããã¹ãã«ãã£ãŠè€æ°åèµ°æ»ãããŸããã»ãã³ãã£ãã¯è§£æãã¹ã¯åãšã©ãŒããã§ãã¯ããæé©åãã¹ã¯ããªãŒãããå¹ççã«æžãæããã³ãŒãçæãã¹ã¯æçµçãªããªãŒãèµ°æ»ããŠãã·ã³ã³ãŒããŸãã¯ãã€ãã³ãŒããåºåããŸããåãã¹ã¯åãããŒã¿æ§é ã«å¯Ÿããç°ãªãæäœã§ãã
- éçè§£æããŒã«ïŒ ãªã³ã¿ãŒãã³ãŒããã©ãŒããã¿ãã»ãã¥ãªãã£ã¹ãã£ããŒãªã©ã®ããŒã«ã¯ãã³ãŒããASTã«è§£æãããã®åŸããŸããŸãªVisitorãå®è¡ããŠãã¿ãŒã³ãèŠã€ããããã¹ã¿ã€ã«ã«ãŒã«ã匷å¶ããããæœåšçãªè匱æ§ãæ€åºãããããŸãã
- ããã¥ã¡ã³ãåŠçïŒDOMïŒïŒ XMLãŸãã¯HTMLããã¥ã¡ã³ããæäœãããšããããªãã¯ããªãŒãæ±ã£ãŠããŸãããžã§ããªãã¯Visitorã¯ããã¹ãŠã®ãªã³ã¯ãæœåºãããããã¹ãŠã®ç»åã倿ããããããã¥ã¡ã³ããç°ãªã圢åŒã«ã·ãªã¢ã«åãããããã®ã«äœ¿çšã§ããŸãã
- UIãã¬ãŒã ã¯ãŒã¯ïŒ ææ°ã®UIãã¬ãŒã ã¯ãŒã¯ã¯ããŠãŒã¶ãŒã€ã³ã¿ãŒãã§ãŒã¹ãã³ã³ããŒãã³ãããªãŒãšããŠè¡šçŸããŸãããã®ããªãŒã®èµ°æ»ã¯ãã¬ã³ããªã³ã°ãç¶æ æŽæ°ã®äŒæïŒReactã®èª¿æŽã¢ã«ãŽãªãºã ã®ããã«ïŒããŸãã¯ã€ãã³ãã®ãã£ã¹ãããã«å¿ èŠã§ãã
- 3Dã°ã©ãã£ãã¯ã¹ã«ãããã·ãŒã³ã°ã©ãïŒ 3Dã·ãŒã³ã¯ãã°ãã°ãªããžã§ã¯ãã®éå±€ãšããŠè¡šçŸãããŸãã倿ãé©çšããããç©çã·ãã¥ã¬ãŒã·ã§ã³ãå®è¡ãããããªããžã§ã¯ããã¬ã³ããªã³ã°ãã€ãã©ã€ã³ã«æå ¥ãããããããã«èµ°æ»ãå¿ èŠã§ãããžã§ããªãã¯ãŠã©ãŒã«ãŒã¯ãã¬ã³ããªã³ã°æäœãé©çšãããã®åŸç©çæŽæ°æäœãé©çšããããã«åå©çšã§ããŸãã
çµè«ïŒæ°ããæœè±¡åã¬ãã«
ãžã§ããªãã¯Visitorãã¿ãŒã³ã¯ãç¹ã«å°çšã®`TreeWalker`ã§å®è£ ãããå ŽåããœãããŠã§ã¢èšèšã«ããã匷åãªé²åã象城ããŸããããã¯ãVisitorãã¿ãŒã³ã®æ¬æ¥ã®çŽæã§ããããŒã¿ãšæäœã®åé¢ããèµ°æ»ã®è€éãªããžãã¯ãåé¢ããããšã§ãããã«é«ããŸãã
åé¡ãäžããããããŒã¿ãèµ°æ»ãæäœãšãã3ã€ã®æç¢ºã§çŽäº€ããã³ã³ããŒãã³ãã«åè§£ããããšã§ãããã¢ãžã¥ãŒã«çã§ä¿å®æ§ãé«ããå ç¢ãªã·ã¹ãã ãæ§ç¯ã§ããŸããã³ã¢ããŒã¿æ§é ãèµ°æ»ã³ãŒãã倿Žããããšãªãæ°ããæäœã远å ã§ããèœåã¯ããœãããŠã§ã¢ã¢ãŒããã¯ãã£ã«ãšã£ãŠèšå¿µç¢çãªåå©ã§ãã`TreeWalker`ã¯ãäœåãã®æ©èœãåããããšãã§ããåå©çšå¯èœãªè³ç£ãšãªããèµ°æ»ããžãã¯ã䜿çšããããã¹ãŠã®å Žæã§äžè²«ããŠãããæ£ããããšãä¿èšŒããŸãã
çè§£ãšã»ããã¢ããã«åææè³ãå¿ èŠã§ããããžã§ããªãã¯ãªããªãŒèµ°æ»Visitorãã¿ãŒã³ã¯ããããžã§ã¯ãã®ã©ã€ããµã€ã¯ã«å šäœã«ããã£ãŠå€§ããªå©çããããããŸããè€éãªéå±€ããŒã¿ãæ±ãããããéçºè ã«ãšã£ãŠãã¯ãªãŒã³ã§æè»æ§ããããæ°žç¶çãªã³ãŒããæžãããã®äžå¯æ¬ ãªããŒã«ã§ãã